home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr25 / me310.zip / UE310C.ZIP / WORD.C < prev    next >
C/C++ Source or Header  |  1988-12-15  |  16KB  |  645 lines

  1. /*
  2.  * The routines in this file implement commands that work word or a
  3.  * paragraph at a time.  There are all sorts of word mode commands.  If I
  4.  * do any sentence mode commands, they are likely to be put in this file. 
  5.  */
  6.  
  7. #include    <stdio.h>
  8. #include    "estruct.h"
  9. #include    "etype.h"
  10. #include    "edef.h"
  11. #include    "elang.h"
  12.  
  13. /* Word wrap on n-spaces. Back-over whatever precedes the point on the current
  14.  * line and stop on the first word-break or the beginning of the line. If we
  15.  * reach the beginning of the line, jump back to the end of the word and start
  16.  * a new line.    Otherwise, break the line at the word-break, eat it, and jump
  17.  * back to the end of the word. Make sure we force the display back to the
  18.  * left edge of the current window
  19.  * Returns TRUE on success, FALSE on errors.
  20.  */
  21. PASCAL NEAR wrapword(f, n)
  22.  
  23. int f;        /* default flag */
  24. int n;        /* numeric argument */
  25.  
  26. {
  27.     register int cnt;    /* size of word wrapped to next line */
  28.     register int c;        /* charector temporary */
  29.  
  30.     /* backup from the <NL> 1 char */
  31.     if (!backchar(FALSE, 1))
  32.         return(FALSE);
  33.  
  34.     /* back up until we aren't in a word,
  35.        make sure there is a break in the line */
  36.     cnt = 0;
  37.     while (((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ')
  38.                 && (c != '\t')) {
  39.         cnt++;
  40.         if (!backchar(FALSE, 1))
  41.             return(FALSE);
  42.         /* if we make it to the beginning, start a new line */
  43.         if (curwp->w_doto == 0) {
  44.             gotoeol(FALSE, 0);
  45.             return(lnewline());
  46.         }
  47.     }
  48.  
  49.     /* delete the forward white space */
  50.     if (!forwdel(0, 1))
  51.         return(FALSE);
  52.  
  53.     /* put in a end of line */
  54.     if (!lnewline())
  55.         return(FALSE);
  56.  
  57.     /* and past the first word */
  58.     while (cnt-- > 0) {
  59.         if (forwchar(FALSE, 1) == FALSE)
  60.             return(FALSE);
  61.     }
  62.  
  63.     /* make sure the display is not horizontally scrolled */
  64.     if (curwp->w_fcol != 0) {
  65.         curwp->w_fcol = 0;
  66.         curwp->w_flag |= WFHARD | WFMOVE | WFMODE;
  67.     }
  68.  
  69.     return(TRUE);
  70. }
  71.  
  72. /*
  73.  * Move the cursor backward by "n" words. All of the details of motion are
  74.  * performed by the "backchar" and "forwchar" routines. Error if you try to
  75.  * move beyond the buffers.
  76.  */
  77. PASCAL NEAR backword(f, n)
  78. {
  79.     if (n < 0)
  80.         return(forwword(f, -n));
  81.     if (backchar(FALSE, 1) == FALSE)
  82.         return(FALSE);
  83.     while (n--) {
  84.         while (inword() == FALSE) {
  85.             if (backchar(FALSE, 1) == FALSE)
  86.                 return(FALSE);
  87.         }
  88.         while (inword() != FALSE) {
  89.             if (backchar(FALSE, 1) == FALSE)
  90.                 return(FALSE);
  91.         }
  92.     }
  93.     return(forwchar(FALSE, 1));
  94. }
  95.  
  96. /*
  97.  * Move the cursor forward by the specified number of words. All of the motion
  98.  * is done by "forwchar". Error if you try and move beyond the buffer's end.
  99.  */
  100. PASCAL NEAR forwword(f, n)
  101. {
  102.     if (n < 0)
  103.         return(backword(f, -n));
  104.     while (n--) {
  105.         /* scan through the current word */
  106.         while (inword() == TRUE) {
  107.             if (forwchar(FALSE, 1) == FALSE)
  108.                 return(FALSE);
  109.         }
  110.  
  111.         /* scan through the intervening white space */
  112.         while (inword() == FALSE) {
  113.             if (forwchar(FALSE, 1) == FALSE)
  114.                 return(FALSE);
  115.         }
  116.     }
  117.     return(TRUE);
  118. }
  119.  
  120. /*
  121.  * Move forward to the end of the nth next word. Error if you move past
  122.  * the end of the buffer.
  123.  */
  124. PASCAL NEAR endword(f, n)
  125. {
  126.     if (n < 0)
  127.         return(backword(f, -n));
  128.     while (n--) {
  129.         /* scan through the intervening white space */
  130.         while (inword() == FALSE) {
  131.             if (forwchar(FALSE, 1) == FALSE)
  132.                 return(FALSE);
  133.         }
  134.  
  135.         /* scan through the current word */
  136.         while (inword() == TRUE) {
  137.             if (forwchar(FALSE, 1) == FALSE)
  138.                 return(FALSE);
  139.         }
  140.     }
  141.     return(TRUE);
  142. }
  143.  
  144. /*
  145.  * Move the cursor forward by the specified number of words. As you move,
  146.  * convert any characters to upper case. Error if you try and move beyond the
  147.  * end of the buffer. Bound to "M-U".
  148.  */
  149. PASCAL NEAR upperword(f, n)
  150. {
  151.     int c;
  152.  
  153.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  154.         return(rdonly());    /* we are in read only mode    */
  155.     if (n < 0)
  156.         return(FALSE);
  157.     while (n--) {
  158.         while (inword() == FALSE) {
  159.             if (forwchar(FALSE, 1) == FALSE)
  160.                 return(FALSE);
  161.         }
  162.         while (inword() != FALSE) {
  163.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  164.             if (islower(c)) {
  165.                 c = upperc(c);
  166.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  167.                 lchange(WFHARD);
  168.             }
  169.             if (forwchar(FALSE, 1) == FALSE)
  170.                 return(FALSE);
  171.         }
  172.     }
  173.     return(TRUE);
  174. }
  175.  
  176. /*
  177.  * Move the cursor forward by the specified number of words. As you move
  178.  * convert characters to lower case. Error if you try and move over the end of
  179.  * the buffer. Bound to "M-L".
  180.  */
  181. PASCAL NEAR lowerword(f, n)
  182. {
  183.     int c;
  184.  
  185.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  186.         return(rdonly());    /* we are in read only mode    */
  187.     if (n < 0)
  188.         return(FALSE);
  189.     while (n--) {
  190.         while (inword() == FALSE) {
  191.             if (forwchar(FALSE, 1) == FALSE)
  192.                 return(FALSE);
  193.         }
  194.         while (inword() != FALSE) {
  195.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  196.             if (isupper(c)) {
  197.                 c = lowerc(c);
  198.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  199.                 lchange(WFHARD);
  200.             }
  201.             if (forwchar(FALSE, 1) == FALSE)
  202.                 return(FALSE);
  203.         }
  204.     }
  205.     return(TRUE);
  206. }
  207.  
  208. /*
  209.  * Move the cursor forward by the specified number of words. As you move
  210.  * convert the first character of the word to upper case, and subsequent
  211.  * characters to lower case. Error if you try and move past the end of the
  212.  * buffer. Bound to "M-C".
  213.  */
  214. PASCAL NEAR capword(f, n)
  215. {
  216.     int c;
  217.  
  218.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  219.         return(rdonly());    /* we are in read only mode    */
  220.     if (n < 0)
  221.         return(FALSE);
  222.     while (n--) {
  223.         while (inword() == FALSE) {
  224.             if (forwchar(FALSE, 1) == FALSE)
  225.                 return(FALSE);
  226.         }
  227.         if (inword() != FALSE) {
  228.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  229.             if (islower(c)) {
  230.                 c = upperc(c);
  231.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  232.                 lchange(WFHARD);
  233.             }
  234.             if (forwchar(FALSE, 1) == FALSE)
  235.                 return(FALSE);
  236.             while (inword() != FALSE) {
  237.                 c = lgetc(curwp->w_dotp, curwp->w_doto);
  238.                 if (isupper(c)) {
  239.                     c = lowerc(c);
  240.                     lputc(curwp->w_dotp, curwp->w_doto, c);
  241.                     lchange(WFHARD);
  242.                 }
  243.                 if (forwchar(FALSE, 1) == FALSE)
  244.                     return(FALSE);
  245.             }
  246.         }
  247.     }
  248.     return(TRUE);
  249. }
  250.  
  251. /*
  252.  * Kill forward by "n" words. Remember the location of dot. Move forward by
  253.  * the right number of words. Put dot back where it was and issue the kill
  254.  * command for the right number of characters. With a zero argument, just
  255.  * kill one word and no whitespace. Bound to "M-D".
  256.  */
  257. PASCAL NEAR delfword(f, n)
  258. {
  259.     register LINE    *dotp;    /* original cursor line */
  260.     register int    doto;    /*    and row */
  261.     register int c;        /* temp char */
  262.     long size;        /* # of chars to delete */
  263.  
  264.     /* don't allow this command if we are in read only mode */
  265.     if (curbp->b_mode&MDVIEW)
  266.         return(rdonly());
  267.  
  268.     /* ignore the command if there is a negative argument */
  269.     if (n < 0)
  270.         return(FALSE);
  271.  
  272.     /* Clear the kill buffer if last command wasn't a kill */
  273.     if ((lastflag&CFKILL) == 0)
  274.         kdelete();
  275.     thisflag |= CFKILL;    /* this command is a kill */
  276.  
  277.     /* save the current cursor position */
  278.     dotp = curwp->w_dotp;
  279.     doto = curwp->w_doto;
  280.  
  281.     /* figure out how many characters to give the axe */
  282.     size = 0;
  283.  
  284.     /* get us into a word.... */
  285.     while (inword() == FALSE) {
  286.         if (forwchar(FALSE, 1) == FALSE)
  287.             return(FALSE);
  288.         ++size;
  289.     }
  290.  
  291.     if (n == 0) {
  292.         /* skip one word, no whitespace! */
  293.         while (inword() == TRUE) {
  294.             if (forwchar(FALSE, 1) == FALSE)
  295.                 return(FALSE);
  296.             ++size;
  297.         }
  298.     } else {
  299.         /* skip n words.... */
  300.         while (n--) {
  301.     
  302.             /* if we are at EOL; skip to the beginning of the next */
  303.             while (curwp->w_doto == llength(curwp->w_dotp)) {
  304.                 if (forwchar(FALSE, 1) == FALSE)
  305.                     return(FALSE);
  306.                 ++size;
  307.             }
  308.     
  309.             /* move forward till we are at the end of the word */
  310.             while (inword() == TRUE) {
  311.                 if (forwchar(FALSE, 1) == FALSE)
  312.                     return(FALSE);
  313.                 ++size;
  314.             }
  315.     
  316.             /* if there are more words, skip the interword stuff */
  317.             if (n != 0)
  318.                 while (inword() == FALSE) {
  319.                     if (forwchar(FALSE, 1) == FALSE)
  320.                         return(FALSE);
  321.                     ++size;
  322.                 }
  323.         }
  324.     
  325.         /* skip whitespace and newlines */
  326.         while ((curwp->w_doto == llength(curwp->w_dotp)) ||
  327.             ((c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ') ||
  328.             (c == '\t')) {
  329.                 if (forwchar(FALSE, 1) == FALSE)
  330.                     break;
  331.                 ++size;
  332.         }
  333.     }
  334.  
  335.     /* restore the original position and delete the words */
  336.     curwp->w_dotp = dotp;
  337.     curwp->w_doto = doto;
  338.     return(ldelete(size, TRUE));
  339. }
  340.  
  341. /*
  342.  * Kill backwards by "n" words. Move backwards by the desired number of words,
  343.  * counting the characters. When dot is finally moved to its resting place,
  344.  * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
  345.  */
  346. PASCAL NEAR delbword(f, n)
  347. {
  348.     long size;
  349.  
  350.     /* don't allow this command if we are in read only mode */
  351.     if (curbp->b_mode&MDVIEW)
  352.         return(rdonly());
  353.  
  354.     /* ignore the command if there is a nonpositive argument */
  355.     if (n <= 0)
  356.         return(FALSE);
  357.  
  358.     /* Clear the kill buffer if last command wasn't a kill */
  359.     if ((lastflag&CFKILL) == 0)
  360.         kdelete();
  361.     thisflag |= CFKILL;    /* this command is a kill */
  362.  
  363.     if (backchar(FALSE, 1) == FALSE)
  364.         return(FALSE);
  365.     size = 0;
  366.     while (n--) {
  367.         while (inword() == FALSE) {
  368.             if (backchar(FALSE, 1) == FALSE)
  369.                 return(FALSE);
  370.             ++size;
  371.         }
  372.         while (inword() != FALSE) {
  373.             ++size;
  374.             if (backchar(FALSE, 1) == FALSE)
  375.                 goto bckdel;
  376.         }
  377.     }
  378.     if (forwchar(FALSE, 1) == FALSE)
  379.         return(FALSE);
  380. bckdel:    return(ldelete(size, TRUE));
  381. }
  382.  
  383. /*
  384.  * Return TRUE if the character at dot is a character that is considered to be
  385.  * part of a word. The word character list is hard coded. Should be setable.
  386.  */
  387. PASCAL NEAR inword()
  388. {
  389.     register int    c;
  390.  
  391.     if (curwp->w_doto == llength(curwp->w_dotp))
  392.         return(FALSE);
  393.     c = lgetc(curwp->w_dotp, curwp->w_doto);
  394.     if (isletter(c))
  395.         return(TRUE);
  396.     if (c>='0' && c<='9')
  397.         return(TRUE);
  398.     return(FALSE);
  399. }
  400.  
  401. #if    WORDPRO
  402. PASCAL NEAR fillpara(f, n)    /* Fill the current paragraph according to the
  403.                current fill column */
  404.  
  405. int f, n;    /* Default flag and Numeric argument */
  406.  
  407. {
  408.     register char *pp;    /* ptr into paragraph being reformed */
  409.     register char *para;    /* malloced buffer for paragraph */
  410.     register LINE *lp;    /* ptr to current line */
  411.     register int lsize;    /* bytes in current line */
  412.     register char *txtptr;    /* ptr into current line */
  413.     LINE *ptline;        /* line the point started on */
  414.     int ptoff;        /* offset of original point */
  415.     int back;        /* # of characters from origin point to eop */
  416.     int status;        /* return status from linstr() */
  417.     int psize;        /* byte size of paragraph */
  418.     LINE *bop;        /* ptr to beg of paragraph */
  419.     LINE *eop;        /* pointer to line just past EOP */
  420.  
  421.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  422.         return(rdonly());    /* we are in read only mode    */
  423.     if (fillcol == 0) {    /* no fill column set */
  424.         mlwrite(TEXT98);
  425. /*                      "No fill column set" */
  426.         return(FALSE);
  427.     }
  428.  
  429.     /* save the original point */
  430.     ptline = curwp->w_dotp;
  431.     ptoff = curwp->w_doto;
  432.  
  433.     /* record the pointer to the line just past the EOP */
  434.     gotoeop(FALSE, 1);
  435.     eop = lforw(curwp->w_dotp);
  436.  
  437.     /* and back top the beginning of the paragraph */
  438.     gotobop(FALSE, 1);
  439.     bop = lp = curwp->w_dotp;
  440.  
  441.     /* ok, how big is this paragraph? */
  442.     psize = 0;
  443.     while (lp != eop) {
  444.         psize += lp->l_used + 1;
  445.         lp = lp->l_fp;
  446.     }
  447.  
  448.     /* create a buffer to hold this stuff */
  449.     para = malloc(psize + 100);    /***** THIS IS TEMP *****/
  450.     if (para == NULL) {
  451.         mlwrite(TEXT99);
  452. /*                      "[OUT OF MEMORY]" */
  453.         return(FALSE);
  454.     }
  455.  
  456.     /* now, grab all the text into a string */
  457.     back = 0;    /* counting the distance to backup when done */
  458.     lp = bop;
  459.     pp = para;
  460.     while (lp != eop) {
  461.         lsize = lp->l_used;
  462.         if (back == 0) {
  463.             if (lp == ptline)
  464.                 back = lsize - ptoff + 1;
  465.         } else
  466.             back += lsize + 1;
  467.         txtptr = lp->l_text;
  468.         while (lsize--)            /* copy a line */
  469.             *pp++ = *txtptr++;
  470.         *pp++ = ' ';            /* turn the NL to a space */
  471.         lp = lp->l_fp;
  472.         lfree(lp->l_bp);        /* free the old line */
  473.     }
  474.     *(--pp) = 0;    /* truncate the last space */
  475.  
  476.     /* reformat the paragraph in the buffer */
  477.     reform(para);
  478.  
  479.     /* insert the reformatted paragraph back into the current buffer */
  480.     status = linstr(para);
  481.     lnewline();        /* add the last newline to our paragraph */
  482.     if (status == TRUE)    /* reposition us to the same place */
  483.         status = backchar(FALSE, back);
  484.  
  485.     /* make sure the display is not horizontally scrolled */
  486.     if (curwp->w_fcol != 0) {
  487.         curwp->w_fcol = 0;
  488.         curwp->w_flag |= WFHARD | WFMOVE | WFMODE;
  489.     }
  490.  
  491.     /* free the buffer and return */
  492.     free(para);
  493.     return(status);
  494. }
  495.  
  496. PASCAL NEAR reform(para)    /* reformat a paragraph as stored in a string */
  497.  
  498. char *para;    /* string buffer containing paragraph */
  499.  
  500. {
  501.     register char *sp;        /* string scan pointer */
  502.     register int col;        /* current colomn position */
  503.     register char *lastword;    /* ptr to end of last word */
  504.  
  505.     /* scan string, replacing some whitespace with newlines */
  506.     sp = para;
  507.     lastword = para;
  508.     col = 0;
  509.     while (*sp) {
  510.         /* if we are at white space.... */
  511.         if ((*sp == ' ') || (*sp == '\t')) {
  512.             if (*sp == '\t')
  513.                 col = (col + 8) & (~7);
  514.             else
  515.                 col++;
  516.  
  517.             /* break on whitespace? */
  518.             if (col >= fillcol) {
  519.                 *sp = '\r';
  520.                 col = 0;
  521.             }
  522.  
  523.             /* onward, resetting the most recent begin of word */
  524.             ++sp;
  525.             lastword = sp;
  526.  
  527.         } else {    /* a non-blank to process */
  528.  
  529.             ++sp;
  530.             ++col;
  531.             if (col >= fillcol) {
  532.                 /* line break here! */
  533.                 if ((lastword > para) &&
  534.                    (*(lastword - 1) != '\r')) {
  535.                        *(lastword - 1) = '\r';
  536.                        sp = lastword;
  537.                        col = 0;
  538.                 }
  539.             }
  540.         }
  541.     }
  542. }
  543.  
  544. PASCAL NEAR killpara(f, n)    /* delete n paragraphs starting with the current one */
  545.  
  546. int f;    /* default flag */
  547. int n;    /* # of paras to delete */
  548.  
  549. {
  550.     register int status;    /* returned status of functions */
  551.  
  552.     while (n--) {        /* for each paragraph to delete */
  553.  
  554.         /* mark out the end and beginning of the para to delete */
  555.         gotoeop(FALSE, 1);
  556.  
  557.         /* set the mark here */
  558.         curwp->w_markp[0] = curwp->w_dotp;
  559.         curwp->w_marko[0] = curwp->w_doto;
  560.  
  561.         /* go to the beginning of the paragraph */
  562.         gotobop(FALSE, 1);
  563.         curwp->w_doto = 0;    /* force us to the beginning of line */
  564.     
  565.         /* and delete it */
  566.         if ((status = killregion(FALSE, 1)) != TRUE)
  567.             return(status);
  568.  
  569.         /* and clean up the 2 extra lines */
  570.         ldelete(2L, TRUE);
  571.     }
  572.     return(TRUE);
  573. }
  574.  
  575.  
  576. /*    wordcount:    count the # of words in the marked region,
  577.             along with average word sizes, # of chars, etc,
  578.             and report on them.            */
  579.  
  580. PASCAL NEAR wordcount(f, n)
  581.  
  582. int f, n;    /* ignored numeric arguments */
  583.  
  584. {
  585.     register LINE *lp;    /* current line to scan */
  586.     register int offset;    /* current char to scan */
  587.     long size;        /* size of region left to count */
  588.     register int ch;    /* current character to scan */
  589.     register int wordflag;    /* are we in a word now? */
  590.     register int lastword;    /* were we just in a word? */
  591.     long nwords;        /* total # of words */
  592.     long nchars;        /* total number of chars */
  593.     int nlines;        /* total number of lines in region */
  594.     int avgch;        /* average number of chars/word */
  595.     int status;        /* status return code */
  596.     REGION region;        /* region to look at */
  597.  
  598.     /* make sure we have a region to count */
  599.     if ((status = getregion(®ion)) != TRUE)
  600.         return(status);
  601.     lp = region.r_linep;
  602.     offset = region.r_offset;
  603.     size = region.r_size;
  604.  
  605.     /* count up things */
  606.     lastword = FALSE;
  607.     nchars = 0L;
  608.     nwords = 0L;
  609.     nlines = 0;
  610.     while (size--) {
  611.  
  612.         /* get the current character */
  613.         if (offset == llength(lp)) {    /* end of line */
  614.             ch = '\r';
  615.             lp = lforw(lp);
  616.             offset = 0;
  617.             ++nlines;
  618.         } else {
  619.             ch = lgetc(lp, offset);
  620.             ++offset;
  621.         }
  622.  
  623.         /* and tabulate it */
  624.         wordflag = ((ch >= 'a' && ch <= 'z') ||
  625.                 (ch >= 'A' && ch <= 'Z') ||
  626.                 (ch >= '0' && ch <= '9'));
  627.         if (wordflag == TRUE && lastword == FALSE)
  628.             ++nwords;
  629.         lastword = wordflag;
  630.         ++nchars;
  631.     }
  632.  
  633.     /* and report on the info */
  634.     if (nwords > 0L)
  635.         avgch = (int)((100L * nchars) / nwords);
  636.     else
  637.         avgch = 0;
  638.  
  639.     mlwrite(TEXT100,
  640. /*              "Words %D Chars %D Lines %d Avg chars/word %f" */
  641.         nwords, nchars, nlines + 1, avgch);
  642.     return(TRUE);
  643. }
  644. #endif
  645.